package com.net.xpay.common.service.impl;

import com.net.xpay.common.domain.partner.*;
import com.net.xpay.common.enums.partner.PartnerCombinationSettleRecordType;
import com.net.xpay.common.helper.PartnerAccountDetailHelper;
import com.net.xpay.core.enums.AccountBillType;
import com.net.xpay.core.manager.PayTransBatchManager;
import com.net.xpay.core.model.PayTransBatchStatResultModel;
import com.net.common.exception.BusinessException;
import com.net.common.util.LocalDateUtil;
import com.net.common.util.SerializationUtil;
import com.net.common.util.StreamUtil;
import com.net.xpay.common.domain.partner.*;
import com.net.xpay.common.manager.partner.PartnerAccountManager;
import com.net.xpay.common.manager.partner.PartnerCombinationSettleRecordManager;
import com.net.xpay.common.manager.partner.PartnerSettleLogManager;
import com.net.xpay.common.manager.partner.PartnerSettleRecordManager;
import com.net.xpay.common.service.PartnerAccountService;
import com.net.xpay.common.service.PartnerSettleInnerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;

/**
 * 2020/9/3 18:35

 */
@Slf4j
@Service
public class PartnerSettleInnerServiceImpl implements PartnerSettleInnerService {

    @Autowired
    private PayTransBatchManager payTransBatchManager;

    @Autowired
    private PartnerSettleRecordManager partnerSettleRecordManager;

    @Autowired
    private PartnerSettleLogManager partnerSettleLogManager;

    @Autowired
    private PartnerAccountDetailHelper partnerAccountDetailHelper;

    @Autowired
    private PartnerAccountManager partnerAccountManager;

    @Autowired
    private PartnerAccountService partnerAccountService;

    @Autowired
    private PartnerCombinationSettleRecordManager partnerCombinationSettleRecordManager;

    /**
     * 统计合伙人佣金
     */
    @Override
    public void doStatPartnerSettleRecord(Partner partner, LocalDate day, PartnerSettleRecord record) {
        LocalDateTime startTime = LocalDateUtil.getDayStart(day);
        LocalDateTime endTime = LocalDateUtil.getDayStart(day.plusDays(1L));
        log.info("doStatPartnerSettleRecord start partnerId={}|day={}|startTime={}|endTime={}", partner.getId(), day, startTime, endTime);
        //一级合伙人收益
        PayTransBatchStatResultModel resultModel1 = payTransBatchManager.statLevelOneSuccessPayTransBatch(partner.getId(), startTime, endTime);
        record.setLevelOneSuccessCount(record.getLevelOneSuccessCount() + resultModel1.getSuccessCount());
        record.setLevelOneBenefit(record.getLevelOneBenefit() + resultModel1.getBenefit());

        record.setSuccessCount(record.getSuccessCount() + resultModel1.getSuccessCount());
        record.setBenefit(record.getBenefit() + resultModel1.getBenefit());
        record.setSuccessAmount(record.getSuccessAmount().add(resultModel1.getSuccessAmount()));
        record.setTransUserCount(record.getTransUserCount() + resultModel1.getTransUserCount());

        //二级合伙人收益
        PayTransBatchStatResultModel resultModel2 = payTransBatchManager.statLevelTwoSuccessPayTransBatch(partner.getId(), startTime, endTime);
        record.setLevelTwoSuccessCount(record.getLevelTwoSuccessCount() + resultModel2.getSuccessCount());
        record.setLevelTwoBenefit(record.getLevelTwoBenefit() + resultModel2.getBenefit());

        record.setSuccessCount(record.getSuccessCount() + resultModel2.getSuccessCount());
        record.setBenefit(record.getBenefit() + resultModel2.getBenefit());
        record.setSuccessAmount(record.getSuccessAmount().add(resultModel2.getSuccessAmount()));
        record.setTransUserCount(record.getTransUserCount() + resultModel2.getTransUserCount());

        log.info("doStatPartnerSettleRecord end partnerId={}|day={}|startTime={}|endTime={}", partner.getId(), day, startTime, endTime);
    }

    /**
     * 结算合伙人佣金
     */
    @Override
    @Transactional(transactionManager = "xpayCommonTransactionManager", rollbackFor = Exception.class)
    public void doSettlePartnerBenefit(Partner partner) {
        log.info("doSettlePartnerBenefit start|partnerId={}", partner.getId());
        //查找合伙人所有待结算的统计记录
        List<PartnerSettleRecord> records = partnerSettleRecordManager.listNoSettled(partner.getId());
        records.sort(Comparator.comparing(PartnerSettleRecord::getDay));
        log.info("doSettlePartnerBenefit records={}", SerializationUtil.obj2String(records));
        if (CollectionUtils.isEmpty(records)) {
            log.info("doSettlePartnerBenefit no records={}", SerializationUtil.obj2String(records));
            return;
        }
        long successCount = 0L;
        long benefit = 0L;
        BigDecimal successAmount = new BigDecimal("0");
        for (PartnerSettleRecord record : records) {
            if (!Objects.equals(record.getPartnerId(), partner.getId())) {
                log.error("invalid record partnerId no matched|partnerId={}|record={}", partner.getId(), SerializationUtil.obj2String(record));
                throw new BusinessException("invalid record partnerId no matched");
            }
            if (record.getSettled()) {
                log.error("invalid record has settled|partnerId={}|record={}", partner.getId(), SerializationUtil.obj2String(record));
                throw new BusinessException("invalid record has settled");
            }

            successCount += record.getSuccessCount();
            successAmount = successAmount.add(record.getSuccessAmount());
            benefit += record.getBenefit();

            record.setSettled(true);
            partnerSettleRecordManager.update(record);
        }

        PartnerSettleLog partnerSettleLog = PartnerSettleLog.getInstance();
        partnerSettleLog.setPartnerId(partner.getId());
        partnerSettleLog.setStartDay(records.get(0).getDay());
        partnerSettleLog.setEndDay(records.get(records.size() - 1).getDay());
        partnerSettleLog.setBenefit(benefit);
        partnerSettleLog.setSuccessCount(successCount);
        partnerSettleLog.setSuccessAmount(successAmount);
        partnerSettleLog.setPartnerSettleRecordIds(StreamUtil.map(records, PartnerSettleRecord::getId));
        partnerSettleLog.setStatSnapJson(SerializationUtil.obj2String(records));
        partnerSettleLogManager.save(partnerSettleLog);

        //将用户维度的结算表也跟新一下
        partnerCombinationSettleRecordManager.updateSettleInfo(partner.getId(), PartnerCombinationSettleRecordType.BATCH_PSW, partnerSettleLog.getStartDay(), partnerSettleLog.getEndDay(), partnerSettleLog.getCreateTime());

        if (partnerSettleLog.getBenefit() == 0L) {
            log.info("doSettlePartnerBenefit no benefit|partnerId={}|snap={}", partner.getId(), partnerSettleLog.getStatSnapJson());
            return;
        }

        //将佣金打入到合伙人账户
        settleBenefitToPartnerAccount(partner, partnerSettleLog);

        log.info("doSettlePartnerBenefit end|partnerId={}", partner.getId());
    }

    private void settleBenefitToPartnerAccount(Partner partner, PartnerSettleLog partnerSettleLog) {
        PartnerAccount partnerAccount = partnerAccountManager.getByIdWithLock(partner.getId());
        PartnerAccountDetail accountDetail = PartnerAccountDetail.getInstance(partner.getId(), partnerSettleLog.getId());
        partnerAccountDetailHelper.initCommonAccountDetail(accountDetail, AccountBillType.PARTNER_BENEFIT_SETTLE, partnerSettleLog.getBenefit(), "分佣结算");
        partnerAccountService.onPay(partner, partnerAccount, accountDetail);
    }

}
